package webWay

import (
	"fmt"
	"log"
	"net/http"
	"reflect"

	"github.com/gin-gonic/gin"
)

const (
	Debug = 0
	Pro   = 1
)

type DataReurn struct {
	Code int    `json:"code"`
	Data any    `json:"data"`
	Msg  string `json:"msg"`
}

// 没有设置group的，通过函数名
func reflectServiceByName(webRouter *gin.Engine, routerPath, serviceName string, serverObj any) {
	webRouter.POST(routerPath, func(ctx *gin.Context) {
		objV := reflect.ValueOf(serverObj)
		serviceV := objV.MethodByName(serviceName)
		// 利用反射创建结构体,grpc结构中，第1个参数context，第2个是自定义参数
		res := reflect.New(serviceV.Type().In(1).Elem()).Interface()
		if err := ctx.ShouldBind(&res); err != nil {
			panic(err)
		}

		args := []reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(res)}
		outs := serviceV.Call(args)
		if outs[1].Type().String() == "error" {
			errInfo, ok := outs[1].Interface().(error)
			if ok {
				ctx.JSONP(400, DataReurn{
					Code: 400,
					Data: "error",
					Msg:  errInfo.Error(),
				})
				return
			}
		}
		ctx.JSONP(200, DataReurn{
			Code: 200,
			Data: outs[0].Interface(),
			Msg:  "success",
		})
	})
}

// 设置group的，通过函数名
func reflectServiceGroupByName(webRouter *gin.RouterGroup, routerPath, serviceName string, serverObj any) {
	webRouter.POST(routerPath, func(ctx *gin.Context) {
		objV := reflect.ValueOf(serverObj)
		serviceV := objV.MethodByName(serviceName)
		// 利用反射创建结构体,grpc结构中，第1个参数context，第2个是自定义参数
		res := reflect.New(serviceV.Type().In(1).Elem()).Interface()
		if err := ctx.ShouldBind(&res); err != nil {
			panic(err)
		}
		args := []reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(res)}
		outs := serviceV.Call(args)
		if outs[1].Type().String() == "error" {
			errInfo, ok := outs[1].Interface().(error)
			if ok {
				ctx.JSONP(400, DataReurn{
					Code: 400,
					Data: "error",
					Msg:  errInfo.Error(),
				})
				return
			}
		}
		ctx.JSONP(200, DataReurn{
			Code: 200,
			Data: outs[0].Interface(),
			Msg:  "success",
		})
	})
}

// 非分组 通过传入函数和入参数，性能相比函数名更高一些
func reflectServiceByFunc(webRouter *gin.Engine, routerPath string, servicFunc, input any) {
	webRouter.POST(routerPath, func(ctx *gin.Context) {
		serviceV := reflect.ValueOf(servicFunc)
		// 利用反射创建结构体
		res := reflect.New(reflect.TypeOf(input).Elem()).Interface()
		if err := ctx.ShouldBind(&res); err != nil {
			panic(err)
		}

		args := []reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(res)}
		outs := serviceV.Call(args)
		if outs[1].Type().String() == "error" {
			errInfo, ok := outs[1].Interface().(error)
			if ok {
				ctx.JSONP(400, DataReurn{
					Code: 400,
					Data: "error",
					Msg:  errInfo.Error(),
				})
				return
			}
		}
		ctx.JSONP(200, DataReurn{
			Code: 200,
			Data: outs[0].Interface(),
			Msg:  "success",
		})
	})
}

// 分组 通过传入函数和入参数，性能相比函数名更高一些
func reflectServiceGroupByFunc(webRouter *gin.RouterGroup, routerPath string, servicFunc, input any) {
	webRouter.POST(routerPath, func(ctx *gin.Context) {
		serviceV := reflect.ValueOf(servicFunc)
		// 利用反射创建结构体
		res := reflect.New(reflect.TypeOf(input).Elem()).Interface()
		if err := ctx.ShouldBind(&res); err != nil {
			panic(err)
		}

		args := []reflect.Value{reflect.ValueOf(ctx), reflect.ValueOf(res)}
		outs := serviceV.Call(args)
		if outs[1].Type().String() == "error" {
			errInfo, ok := outs[1].Interface().(error)
			if ok {
				ctx.JSONP(400, DataReurn{
					Code: 400,
					Data: "error",
					Msg:  errInfo.Error(),
				})
				return
			}
		}
		ctx.JSONP(200, DataReurn{
			Code: 200,
			Data: outs[0].Interface(),
			Msg:  "success",
		})
	})
}

type webWayObj struct {
	addr      string
	webRouter *gin.Engine
	webGroup  *gin.RouterGroup
}

// 新建一个webWay对象,控制进入生产模式，还是debug模式
// 参数说明(模式id, 监听域名+端口, gin中间件)
func NewWebWay(env int, addr string, middleware ...gin.HandlerFunc) *webWayObj {
	var webRouter *gin.Engine
	if env == Pro {
		gin.SetMode(gin.ReleaseMode)
		webRouter = gin.New()
	} else {
		webRouter = gin.Default()
	}
	webRouter.Use(middleware...)
	return &webWayObj{
		addr:      addr,
		webRouter: webRouter,
		webGroup:  nil,
	}
}

// 设置分组
// 参数说明(分组前缀, gin中间件)
// 兼容组下分组
func (w *webWayObj) NewGroup(groupPath string, middleware ...gin.HandlerFunc) *webWayObj {
	var webGroup *gin.RouterGroup
	if w.webGroup != nil {
		webGroup = w.webGroup.Group(groupPath, middleware...)
	} else {
		webGroup = w.webRouter.Group(groupPath, middleware...)
	}

	return &webWayObj{
		addr:      w.addr,
		webRouter: w.webRouter,
		webGroup:  webGroup,
	}
}

// 反射执行
// 通过函数名进行放射
// 参数说明(路由名, grpc的方法名, grpc的实例对象)
func (w *webWayObj) RegisterServiceByName(routerPath, serviceName string, serverObj any) {
	if w.webGroup != nil {
		reflectServiceGroupByName(w.webGroup, routerPath, serviceName, serverObj)
	} else {
		reflectServiceByName(w.webRouter, routerPath, serviceName, serverObj)
	}
}

// 通过传入方法进行反射
// 参数说明(路由名, grpc方法, grpc方法的入参[要为指针类型])
func (w *webWayObj) RegisterServiceByFunc(routerPath string, serviceFunc, input any) {
	if w.webGroup != nil {
		reflectServiceGroupByFunc(w.webGroup, routerPath, serviceFunc, input)
	} else {
		reflectServiceByFunc(w.webRouter, routerPath, serviceFunc, input)
	}
}

// 获取Engine
func (w *webWayObj) GetRouter() *gin.Engine {
	return w.webRouter
}

// 获取Group
func (w *webWayObj) GetGroup() *gin.RouterGroup {
	return w.webGroup
}

// 生产默认启动
func (w *webWayObj) ServerStart() {
	srv := &http.Server{
		Addr:    w.addr,
		Handler: w.webRouter,
	}
	go func() {
		// 服务连接
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()
	fmt.Printf("http server start: %v\n", w.addr)
}
